home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-01-15 | 17.0 KB | 729 lines | [TEXT/PJMM] |
- program pong;
-
- uses
- {$IFC UNDEFINED THINK_PASCAL}
- Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
- Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
- GestaltEqu, Files, Errors, Devices, QuickDrawText, TextUtils,{}
- {$ENDC}
- Sound;
-
- (* pong.c}
- { The classic game of pong in Megamax C for the Mac.}
- { Thanks to MacTutor (Vol 1, No. 5 April 1985 page 39) for }
- { animation techniques. If you are reading this and don't }
- { subscribe to MacTutor, consider it. No resource file is }
- { needed. This program, source and object, is in the}
- { public domain and not for sale. }
- { }
- { Author : David L. O'Connor, 370 Eden St. Buffalo, N.Y. }
- { 14220. (716) 828-0898. CIS - 70265,1172 }
- { Date : July, 1985 Version 2}
- { }
- { }
- { Changes by Ingemar 1996:}
- { - Speed limit}
- { - Keyboard equivalents}
- { - Modern #includes}
- { - GetOSEvent makes it acceptably fast}
- {*)
-
- (* the game diRections *)
- const
- STOPPED = 0;
- UP = 1;
- DOWN = 2;
- LEFT = 3;
- RIGHT = 4;
- UP_LEFT = 5;
- UP_RIGHT = 6;
- DOWN_LEFT = 7;
- DOWN_RIGHT = 8;
-
- (* paddle + ball dimensions *)
- PADWIDTH = 10;
- PADLENGTH = 45;
- PADINSET = 10;
- BALLWIDTH = 9;
- BALLLENGTH = 9;
-
- BALLSPEED = 7;
- PADDLESPEED = 9;
- HIGHSCORE = 21;
-
- (* the menu ids *)
- appleid = 128;
- fileid = 129;
- editid = 130;
- skillid = 131;
- soundid = 132;
-
- (* from the MAC's standard pattern list *)
- {PAD_PAT= ((*pat_Handle)->pat_list[6]);}
- {WALL_PAT= ((*pat_Handle)->pat_list[10]);}
- var
- PAD_PAT: Pattern;
- WALL_PAT: Pattern;
-
- type
- sys_patterns = record
- pat_cnt: Integer;
- pat_list: array[0..37] of Pattern;
- end;
- SysPatternPtr = ^sys_patterns;
- SysPatternHnd = ^SysPatternPtr;
-
- type
- paddle = record
- r: Rect;
- dir: Integer;
- speed: Integer;
- score: Integer;
- end;
-
- type
- target = record
- Rgn: RgnHandle;
- oldRgn: RgnHandle;
- unRgn: RgnHandle;
- dir: Integer;
- speed: Integer;
- on: Boolean;
- end;
-
- type
- bleep_tag = record
- mode: Integer;
- triplet: array[0..0] of Tone;
- end;
-
- type
- blat_tag = record
- mode: Integer;
- triplet: array[0..1] of Tone;
- end;
-
- var
- bleep_buf: bleep_tag;
- blat_buf: blat_tag;
- l_paddle, r_paddle: paddle;
- ball: target;
- pat_Handle: SysPatternHnd;
- gamewindow, which_window: WindowPtr;
- winstorage: WindowRecord;
- r, dragRect, top_wall, bottom_wall: Rect;
- gameEvent: EventRecord;
- gamemenu: array[0..4] of MenuHandle;
- menutitle: array[0..0] of char;
- skill_level, last_won, volleys: Integer;
- done, paused, sound_on: Boolean;
-
- const
- kTitle = ' Left 00 MAC_Pong Right 00 ';
- var
- title: Str255;
-
- (* Every so often, let the Mac's paddle fail to track the ball until}
- { the ball has passed it by a certain amount.}
- { This is the heart of a satisfying game. *)
-
- function handicap: Integer;
- var
- mac_skill: Integer;
- begin
- case skill_level of
- 1:
- mac_skill := 2;
- 2:
- mac_skill := 8;
- 3:
- mac_skill := 27;
- 4:
- mac_skill := 64;
- otherwise
- mac_skill := 2;
- end; {case}
- if Random mod mac_skill = 0 then
- handicap := 5
- else
- handicap := 0;
- end;
-
- procedure blat;
- begin
- if (sound_on) then
- begin
- if (not SoundDone) then
- StopSound;
- StartSound(Ptr(@blat_buf), sizeof(blat_buf), nil);
- end;
- end;
-
- procedure bleep;
- begin
- if (sound_on) then
- begin
- if (not SoundDone) then
- StopSound;
- StartSound(Ptr(@bleep_buf), sizeof(bleep_buf), nil);
- end;
- end;
-
- procedure display_score;
- var
- i: LongInt;
- begin
- i := l_paddle.score;
- title[15] := Char($30 + (i div 100));
- title[16] := Char($30 + ((i mod 100) div 10));
- title[17] := Char($30 + (i mod 10));
- i := r_paddle.score;
- title[63] := Char($30 + (i div 100));
- title[64] := Char($30 + ((i mod 100) div 10));
- title[65] := Char($30 + (i mod 10));
- SetWTitle(gamewindow, title);
- end;
-
- (* the ball eats the walls and paddles *)
-
- procedure recover_from_collision;
- var
- rp: Rect;
- begin
- rp := ball.unRgn^^.rgnBBox;
-
- if (SectRect(rp, top_wall, r)) then
- FillRect(r, WALL_PAT)
- else if (SectRect(rp, bottom_wall, r)) then
- FillRect(r, WALL_PAT);
- if (SectRect(rp, l_paddle.r, r)) then
- FillRect(r, PAD_PAT)
- else if (SectRect(rp, r_paddle.r, r)) then
- FillRect(r, PAD_PAT);
- end;
-
- procedure move_ball;
- begin
- if (ball.on) then
- begin
- CopyRgn(ball.Rgn, ball.oldRgn);
- case ball.dir of
- LEFT:
- OffsetRgn(ball.Rgn, -ball.speed, 0);
- RIGHT:
- OffsetRgn(ball.Rgn, ball.speed, 0);
- UP_LEFT:
- OffsetRgn(ball.Rgn, -ball.speed, -ball.speed);
- UP_RIGHT:
- OffsetRgn(ball.Rgn, ball.speed, -ball.speed);
- DOWN_LEFT:
- OffsetRgn(ball.Rgn, -ball.speed, ball.speed);
- DOWN_RIGHT:
- OffsetRgn(ball.Rgn, ball.speed, ball.speed);
- end; {case}
- UnionRgn(ball.Rgn, ball.oldRgn, ball.unRgn);
- DiffRgn(ball.unRgn, ball.Rgn, ball.unRgn);
- EraseRgn(ball.unRgn);
- PaintRgn(ball.Rgn);
- recover_from_collision;
- end;
- end;
-
- procedure move_right_paddle;
- begin
- if (r_paddle.dir = STOPPED) then
- FillRect(r_paddle.r, PAD_PAT)
- else
- begin
- r.left := r_paddle.r.left;
- r.right := r_paddle.r.right;
- case r_paddle.dir of
- UP:
- begin
- r.bottom := r_paddle.r.bottom;
- r_paddle.r.top := r_paddle.r.top - r_paddle.speed;
- r_paddle.r.bottom := r_paddle.r.bottom - r_paddle.speed;
- r.top := r_paddle.r.bottom;
- end;
- DOWN:
- begin
- r.top := r_paddle.r.top;
- r_paddle.r.top := r_paddle.r.top + r_paddle.speed;
- r_paddle.r.bottom := r_paddle.r.bottom + r_paddle.speed;
- r.bottom := r_paddle.r.top;
- end;
- end;
- EraseRect(r);
- FillRect(r_paddle.r, PAD_PAT);
- end;
- end;
-
- procedure move_left_paddle;
- var
- mouseloc: Point;
- newtop, newbottom: Integer;
- begin
- GetMouse(mouseloc);
- if (mouseloc.v <> l_paddle.r.top) then
- begin
- r.left := l_paddle.r.left;
- r.right := l_paddle.r.right;
- if (mouseloc.v <= winstorage.port.portRect.top) then
- begin
- newtop := winstorage.port.portRect.top;
- newbottom := newtop + PADLENGTH;
- end
- else if (mouseloc.v + PADLENGTH >= winstorage.port.portRect.bottom) then
- begin
- newbottom := winstorage.port.portRect.bottom;
- newtop := newbottom - PADLENGTH;
- end
- else
- begin
- newtop := mouseloc.v;
- newbottom := newtop + PADLENGTH;
- end;
- if (newtop > l_paddle.r.top) then
- begin
- r.top := l_paddle.r.top;
- if newtop > l_paddle.r.bottom then
- r.bottom := l_paddle.r.bottom
- else
- r.bottom := newtop;
- end
- else if (newtop < l_paddle.r.top) then
- begin
- r.bottom := l_paddle.r.bottom;
- if (newbottom < l_paddle.r.top) then
- r.top := l_paddle.r.top
- else
- r.top := newbottom;
- end;
- l_paddle.r.top := newtop;
- l_paddle.r.bottom := newbottom;
- EraseRect(r);
- FillRect(l_paddle.r, PAD_PAT);
- end
- else
- FillRect(l_paddle.r, PAD_PAT);
- end;
-
- (* someone scored a point *)
- procedure kill_ball;
- begin
- ball.on := false;
- volleys := 0;
- CopyRgn(ball.Rgn, ball.unRgn);
- EraseRgn(ball.Rgn);
- recover_from_collision;
- blat;
- display_score;
- end;
-
- (* check for bounces, diRection changes, scoring, etc *)
- procedure check_status;
- var
- ball_r: Rect;
- ball_top, ball_bottom, ball_left, ball_right: Integer;
- begin
- ball_top := ball.Rgn^^.rgnBBox.top;
- ball_bottom := ball.Rgn^^.rgnBBox.bottom;
- ball_left := ball.Rgn^^.rgnBBox.left;
- ball_right := ball.Rgn^^.rgnBBox.right;
-
- ball_r := ball.Rgn^^.rgnBBox;
-
- (* make it a little harder as time goes by *)
- if (volleys > 35) then
- ball.speed := BALLSPEED + 6
- else if (volleys > 30) then
- ball.speed := BALLSPEED + 5
- else if (volleys > 25) then
- ball.speed := BALLSPEED + 4
- else if (volleys > 20) then
- ball.speed := BALLSPEED + 3
- else if (volleys > 15) then
- ball.speed := BALLSPEED + 2
- else if (volleys > 10) then
- ball.speed := BALLSPEED + 1;
-
- r_paddle.speed := ball.speed + 2;
-
- (* the right paddle tries to track the ball *)
- if ((ball_right > 250) and (ball.dir = UP_RIGHT) or (ball.dir = DOWN_RIGHT) or (ball.dir = RIGHT)) then
- begin
- if (ball_top + handicap < r_paddle.r.top) then
- r_paddle.dir := UP
- else if (ball_bottom - handicap > r_paddle.r.bottom) then
- r_paddle.dir := DOWN
- else
- r_paddle.dir := STOPPED;
- end
- else
- r_paddle.dir := STOPPED;
-
- (* the ball and the left boundry *)
- if (ball_left < l_paddle.r.right) then
- begin
- if (SectRect(ball_r, l_paddle.r, r)) then
- begin
- volleys := volleys + 1;
- bleep;
- if (ball_top <= l_paddle.r.top + 15) then
- ball.dir := UP_RIGHT
- else if (ball_top > l_paddle.r.top + 15) and (ball_bottom < l_paddle.r.top + 30) then
- ball.dir := RIGHT
- else
- ball.dir := DOWN_RIGHT;
- end
- else
- begin
- last_won := RIGHT;
- r_paddle.score := r_paddle.score + 1;
- kill_ball;
- end;
- Exit(check_status);
- end;
-
- (* the ball and the right boundry *)
- if (ball_right > r_paddle.r.left) then
- begin
- if (SectRect(ball_r, r_paddle.r, r)) then
- begin
- volleys := volleys + 1;
- bleep;
- if (ball_top <= r_paddle.r.top + 15) then
- ball.dir := UP_LEFT
- else if (ball_top > r_paddle.r.top + 15) and (ball_bottom < r_paddle.r.top + 30) then
- ball.dir := LEFT
- else
- ball.dir := DOWN_LEFT;
- end
- else
- begin
- last_won := LEFT;
- l_paddle.score := l_paddle.score + 1;
- kill_ball;
- end;
- Exit(check_status);
- end;
-
- (* the ball and the top wall *)
- if (ball_top < top_wall.bottom) then
- begin
- if (ball.dir = UP_LEFT) then
- ball.dir := DOWN_LEFT
- else if (ball.dir = UP_RIGHT) then
- ball.dir := DOWN_RIGHT;
- bleep;
- Exit(check_status);
- end;
-
- (* the ball and the bottom wall *)
- if (ball_bottom > bottom_wall.top) then
- begin
- if (ball.dir = DOWN_LEFT) then
- ball.dir := UP_LEFT
- else if (ball.dir = DOWN_RIGHT) then
- ball.dir := UP_RIGHT;
- bleep;
- Exit(check_status);
- end;
- end; {check_status}
-
- procedure Init_game;
- begin
- l_paddle.score := 0;
- r_paddle.score := 0;
- ball.speed := BALLSPEED;
- kill_ball;
- end;
-
- procedure serve_ball;
- var
- i: Integer;
- begin
- OffsetRgn(ball.Rgn, 250 - ball.Rgn^^.rgnBBox.right, 150 - (ball.Rgn^^.rgnBBox.top));
- for i := 0 to 249 do
- begin
- check_status;
- move_right_paddle;
- move_left_paddle;
- move_ball;
- end;
- if last_won = RIGHT then
- ball.dir := LEFT
- else
- ball.dir := RIGHT;
- ball.speed := BALLSPEED;
- ball.on := true;
- PaintRgn(ball.Rgn);
- bleep;
- end;
-
- procedure create_ball;
- begin
- ball.Rgn := NewRgn;
- ball.oldRgn := NewRgn;
- ball.unRgn := NewRgn;
- ball.dir := LEFT;
- ball.speed := BALLSPEED;
- SetRect(r, 250, 150, 250 + BALLWIDTH, 150 + BALLLENGTH);
- OpenRgn;
- FrameOval(r);
- CloseRgn(ball.Rgn);
- end;
-
- procedure create_walls;
- begin
- SetRect(top_wall, winstorage.port.portRect.left + 20, winstorage.port.portRect.top + 5, winstorage.port.portRect.right - 20, winstorage.port.portRect.top + 20);
- FillRect(top_wall, WALL_PAT);
- SetRect(bottom_wall, winstorage.port.portRect.left + 20, winstorage.port.portRect.bottom - 20, winstorage.port.portRect.right - 20, winstorage.port.portRect.bottom - 5);
- FillRect(bottom_wall, WALL_PAT);
- end;
-
- procedure create_r_paddle;
- begin
- r_paddle.dir := STOPPED;
- r_paddle.speed := PADDLESPEED;
- r_paddle.score := 0;
- SetRect(r_paddle.r, winstorage.port.portRect.right - PADWIDTH - PADINSET, winstorage.port.portRect.top + PADINSET, winstorage.port.portRect.right - PADWIDTH - PADINSET + PADWIDTH, winstorage.port.portRect.top + PADINSET + PADLENGTH);
- FillRect(r_paddle.r, PAD_PAT);
- end;
-
- procedure create_l_paddle;
- begin
- l_paddle.dir := STOPPED;
- l_paddle.speed := PADDLESPEED;
- l_paddle.score := 0;
- SetRect(l_paddle.r, winstorage.port.portRect.left + PADINSET, winstorage.port.portRect.top + PADINSET, winstorage.port.portRect.left + PADINSET + PADWIDTH, winstorage.port.portRect.top + PADINSET + PADLENGTH);
- FillRect(l_paddle.r, PAD_PAT);
- end;
-
- procedure DoCommand (menu_selection: LongInt);
- var
- the_item: Integer;
- name: Str255;
- begin
- the_item := LoWord(menu_selection);
- case HiWord(menu_selection) of
- appleid:
- begin
- GetItem(gamemenu[0], the_item, name);
- if OpenDeskAcc(name) <> noErr then
- ;
- SetPort(gamewindow);
- end;
- editid:
- if SystemEdit(the_item - 1) then
- ;
- fileid:
- case (the_item) of
- 1:
- if (paused) then
- begin
- paused := false;
- SetItem(gamemenu[1], 1, 'Pause');
- end
- else
- begin
- paused := true;
- SetItem(gamemenu[1], 1, 'Continue');
- end;
- 2:
- Init_game;
- 3:
- done := true;
- end;
- skillid:
- begin
- CheckItem(gamemenu[3], skill_level, false);
- skill_level := the_item;
- CheckItem(gamemenu[3], skill_level, true);
- end;
- soundid:
- if sound_on then
- begin
- sound_on := false;
- SetItem(gamemenu[4], 1, 'Sound On');
- end
- else
- begin
- sound_on := true;
- SetItem(gamemenu[4], 1, 'Sound Off');
- end;
- end;
- HiliteMenu(0);
- end;
-
- procedure enable_edit_menu;
- begin
- EnableItem(gamemenu[2], 1);
- EnableItem(gamemenu[2], 3);
- EnableItem(gamemenu[2], 4);
- EnableItem(gamemenu[2], 5);
- EnableItem(gamemenu[2], 6);
- end;
-
- procedure disable_edit_menu;
- begin
- DisableItem(gamemenu[2], 1);
- DisableItem(gamemenu[2], 3);
- DisableItem(gamemenu[2], 4);
- DisableItem(gamemenu[2], 5);
- DisableItem(gamemenu[2], 6);
- end;
-
- procedure build_menus;
- var
- i: Integer;
- begin
- InitMenus;
- gamemenu[0] := NewMenu(appleid, '');
- gamemenu[1] := NewMenu(fileid, 'File');
- gamemenu[2] := NewMenu(editid, 'Edit');
- gamemenu[3] := NewMenu(skillid, 'Skill');
- gamemenu[4] := NewMenu(soundid, 'Sound');
- AppendMenu(gamemenu[0], '(About MacPong…;(-');
- AddResMenu(gamemenu[0], 'DRVR');
- AppendMenu(gamemenu[1], 'Pause/P;Restart/R;Quit/Q');
- AppendMenu(gamemenu[2], '(Undo;(-;(Cut;(Copy;(Paste;(Clear');
- AppendMenu(gamemenu[3], 'Beginner;Novice;Normal;Expert');
- AppendMenu(gamemenu[4], 'Sound Off/S');
- for i := 0 to 4 do
- InsertMenu(gamemenu[i], 0);
- CheckItem(gamemenu[3], skill_level, true);
- DrawMenuBar;
- end;
-
- procedure InitSounds;
- begin
- bleep_buf.mode := swMode;
- bleep_buf.triplet[0].count := 1000;
- bleep_buf.triplet[0].amplitude := 255;
- bleep_buf.triplet[0].duration := 5;
- blat_buf.mode := swMode;
- blat_buf.triplet[0].count := 1000;
- blat_buf.triplet[0].amplitude := 255;
- blat_buf.triplet[0].duration := 5;
- blat_buf.triplet[1].count := 3000;
- blat_buf.triplet[1].amplitude := 255;
- blat_buf.triplet[1].duration := 10;
- end;
-
- procedure play_pong;
- var
- startTicks: LongInt;
- begin
- if not paused and ((l_paddle.score < HIGHSCORE) and (r_paddle.score < HIGHSCORE)) then
- begin
- startTicks := TickCount;
- if (not ball.on) then
- serve_ball;
- check_status;
- move_left_paddle;
- move_right_paddle;
- move_ball;
- while (startTicks = TickCount) do
- ;
- end;
- end;
-
- (* pretty much straight from SAMP in I.M. *)
- procedure Handle_Events;
- var
- ch: Char;
- mResult: Longint;
- theMenu, theItem: Integer;
- begin
- SystemTask;
- {if GetNextEvent(everyEvent, gameEvent) then}
- if GetOSEvent(everyEvent, gameEvent) then
- begin
- case gameEvent.what of
- mouseDown:
- case FindWindow(gameEvent.where, which_window) of
- inMenuBar:
- DoCommand(MenuSelect(gameEvent.where));
- inSysWindow:
- SystemClick(gameEvent, which_window);
- inDrag:
- DragWindow(which_window, gameEvent.where, dragRect);
- inContent:
- if (which_window <> FrontWindow) then
- SelectWindow(which_window);
- end;
-
- keyDown, autoKey:
- begin
- ch := Char(BAnd(gameEvent.message, charCodeMask));
- mResult := MenuKey(ch);
- theMenu := HiWord(mResult);
- theItem := LoWord(mResult);
- if (theMenu <> 0) then
- DoCommand(mResult);
- end;
-
- updateEvt:
- begin
- SetPort(gamewindow);
- BeginUpdate(gamewindow);
- FillRect(l_paddle.r, PAD_PAT);
- FillRect(r_paddle.r, PAD_PAT);
- FillRect(top_wall, WALL_PAT);
- FillRect(bottom_wall, WALL_PAT);
- if (ball.on) then
- PaintRgn(ball.Rgn);
- EndUpdate(gamewindow);
- end;
- end;
- end;
- end; { Handle_Events}
-
- procedure setup;
- begin
- done := false;
- skill_level := 2;
- sound_on := true;
- last_won := RIGHT;
- {$IFC UNDEFINED THINK_PASCAL}
- InitGraf(thePort);
- InitFonts;
- InitWindows;
- TEInit;
- InitDialogs(nil);
- InitCursor;
- {$ENDC}
- InitSounds;
-
- pat_Handle := SysPatternHnd(GetResource('PAT#', 0));
- PAD_PAT := pat_Handle^^.pat_list[6];
- WALL_PAT := pat_Handle^^.pat_list[10];
- title := kTitle;
-
- FlushEvents(everyEvent, 0);
- SetRect(r, 4, 40, 508, 338);
- SetRect(dragRect, 4, 24, r.right - 4, r.bottom - 4);
- gamewindow := NewWindow(@winstorage, r, title, true, 0, WindowPtr(-1), false, 0);
- SetPort(gamewindow);
- build_menus;
- ShowCursor;
- create_l_paddle;
- create_r_paddle;
- create_walls;
- create_ball;
- Init_game;
- end;
-
- {main}
- begin
- setup;
- while (not done) do
- begin
- Handle_Events;
- play_pong;
- end;
- FlushEvents(everyEvent, 0);
- StopSound;
- ExitToShell;
- end.